/*
 * Copyright (c) 2016, All rights reserved.
 */
package com.dq.health.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

/**
 * 数字工具类
 *
 * @author nameless
 * @date 2018/10/26
 */
public class NumberUtil extends org.apache.commons.lang3.math.NumberUtils {

    /**
     * 汉语中数字大写
     */
    private static final String[] CN_UPPER_NUMBER = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    /**
     * 汉语中货币单位大写，这样的设计类似于占位符
     */
    private static final String[] CN_UPPER_MONETRAY_UNIT =
        {"分", "角", "元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾", "佰", "仟"};
    /**
     * 特殊字符：整
     */
    private static final String CN_FULL = "整";
    /**
     * 特殊字符：负
     */
    private static final String CN_NEGATIVE = "负";
    /**
     * 金额的精度，默认值为2
     */
    private static final int MONEY_PRECISION = 2;
    /**
     * 特殊字符：零元整
     */
    private static final String CN_ZEOR_FULL = "零元" + CN_FULL;

    /**
     * 缩放比例：100
     */
    public static final int SCALE_HUNDRED = 100;

    /**
     * 缩放比例：1000
     */
    public static final int SCALE_THOUSAND = 1000;

    /**
     * 缩放比例：10000
     */
    public static final int SCALE_TEN_THOUSAND = 10000;

    /**
     * 把输入的金额转换为汉语中人民币的大写
     *
     * @param numberOfMoney 输入的金额
     * @return 对应的汉语大写
     */
    public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
        StringBuffer sb = new StringBuffer();
        // -1, 0, or 1 as the value of this BigDecimal is negative, zero, or
        // positive.
        int signum = numberOfMoney.signum();
        // 零元整的情况
        if (signum == 0) {
            return CN_ZEOR_FULL;
        }
        // 这里会进行金额的四舍五入
        long number = numberOfMoney.movePointRight(MONEY_PRECISION).setScale(0, 4).abs().longValue();
        // 得到小数点后两位值
        long scale = number % 100;
        int numUnit = 0;
        int numIndex = 0;
        boolean getZero = false;
        // 判断最后两位数，一共有四中情况：00 = 0, 01 = 1, 10, 11
        if (!(scale > 0)) {
            numIndex = 2;
            number = number / 100;
            getZero = true;
        }
        if ((scale > 0) && (!(scale % 10 > 0))) {
            numIndex = 1;
            number = number / 10;
            getZero = true;
        }
        int zeroSize = 0;
        while (true) {
            if (number <= 0) {
                break;
            }
            // 每次获取到最后一个数
            numUnit = (int)(number % 10);
            if (numUnit > 0) {
                if ((numIndex == 9) && (zeroSize >= 3)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
                }
                if ((numIndex == 13) && (zeroSize >= 3)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
                }
                sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                sb.insert(0, CN_UPPER_NUMBER[numUnit]);
                getZero = false;
                zeroSize = 0;
            } else {
                ++zeroSize;
                if (!(getZero)) {
                    sb.insert(0, CN_UPPER_NUMBER[numUnit]);
                }
                if (numIndex == 2) {
                    if (number > 0) {
                        sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                    }
                } else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                }
                getZero = true;
            }
            // 让number每次都去掉最后一个数
            number = number / 10;
            ++numIndex;
        }
        // 如果signum == -1，则说明输入的数字为负数，就在最前面追加特殊字符：负
        if (signum == -1) {
            sb.insert(0, CN_NEGATIVE);
        }
        // 输入的数字小数点后两位为"00"的情况，则要在最后追加特殊字符：整
        if (!(scale > 0)) {
            sb.append(CN_FULL);
        }
        return sb.toString();
    }

    /**
     * 补齐0
     *
     * @param number 序列
     * @param count 补齐到多少位
     * @return
     */
    public static String fillZero(Integer number, int count) {
        String numStr = number + "";
        String retStr = "";
        for (int i = 0; i < count; i++) {
            retStr += "0";
        }
        return retStr.substring(numStr.length()) + numStr;
    }

    /**
     * 获取最大值
     *
     * @param values
     * @return
     */
    public static Integer max(Integer... values) {
        Integer maxValue = Integer.MIN_VALUE;
        for (Integer value : values) {
            if (null == value) {
                continue;
            }
            maxValue = Math.max(maxValue, value);
        }
        if (maxValue == Integer.MIN_VALUE) {
            return 0;
        } else {
            return maxValue;
        }
    }

    /**
     * 获取最小值
     *
     * @param values
     * @return
     */
    public static Integer min(Integer... values) {
        Integer minValue = Integer.MAX_VALUE;
        for (Integer value : values) {
            if (null == value) {
                continue;
            }
            minValue = Math.min(minValue, value);
        }
        if (minValue == Integer.MAX_VALUE) {
            return 0;
        } else {
            return minValue;
        }
    }

    /**
     * 把字符串数据扩大指定倍数，返回整型数据
     *
     * @param value
     * @param scale
     * @return
     * @author liangranhui
     * @date 2019/9/17 14:03
     */
    public static Integer enlarge(String value, int scale) {
        if (value == null || value == "") {
            return null;
        }
        Integer digit = 0;
        if (scale <= 0) {
            return new BigDecimal(value).setScale(digit, RoundingMode.HALF_UP).intValue();
        }
        int newScale = scale / 10;
        while (true) {
            if (newScale <= 0) {
                break;
            }
            newScale = newScale / 10;
            digit++;
        }
        return new BigDecimal(value).setScale(digit, RoundingMode.HALF_UP).multiply(new BigDecimal(scale)).intValue();
    }

    /**
     * 把整型数据缩小指定倍数，返回字符串数据
     *
     * @param value
     * @param scale
     * @return
     * @author liangranhui
     * @date 2019/9/17 14:08
     */
    public static String shrink(Integer value, int scale) {
        if (value == null) {
            return null;
        }
        Integer digit = 0;
        if (scale <= 0) {
            return new BigDecimal(value).setScale(digit, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
        }
        int newScale = scale / 10;
        while (true) {
            if (newScale <= 0) {
                break;
            }
            newScale = newScale / 10;
            digit++;
        }
        return new BigDecimal(value).divide(new BigDecimal(scale)).setScale(digit, RoundingMode.HALF_UP)
            .stripTrailingZeros().toPlainString();
    }

    /**
     * 元转成分
     *
     * @param price
     * @return
     */
    public static String changeFenToYuan(Integer price) {
        if (price == null) {
            return "";
        }
        return BigDecimal.valueOf(price).divide(new BigDecimal("100")).toString();
    }

    /**
     * 元转成分
     *
     * @param price
     * @return
     */
    public static String changeFenToYuan(Long price) {
        if (price == null) {
            return "";
        }
        return BigDecimal.valueOf(price).divide(new BigDecimal("100")).toString();
    }

    /**
     * 功能描述: 元转成分
     *
     * @Author: chenxin
     * @Date: 2020/3/25
     */
    public static BigDecimal changeFenToYuanToBigDecimal(Integer price) {
        if (price == null) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(price).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 功能描述: 元转成分
     *
     * @Author: chenxin
     * @Date: 2020/3/25
     */
    public static BigDecimal changeFenToYuanToBigDecimal(Long price) {
        if (price == null) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(price).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 字符串元，转为整形分
     * 
     * @param str
     * @return
     */
    public static Integer yuanToFen(final String str) {

        try {
            // 字符串内没有小数点，直接乘以100后返回
            if (-1 == str.indexOf(".")) {
                return Integer.valueOf(str) * 100;
            }
            String[] splited = str.split("\\.");
            if (splited.length > 2) {
                throw new RuntimeException();
            }
            Integer fen = Integer.valueOf(splited[0]) * 100;
            String strFen = splited[1];
            if (strFen.length() == 1) {
                fen += Integer.valueOf(strFen) * 10;
            } else if (strFen.length() == 2) {
                fen += Integer.valueOf(strFen);
            } else {
                strFen = strFen.substring(0, 2);
                fen += Integer.valueOf(strFen);
            }

            return fen;
        } catch (Exception e) {
            throw new RuntimeException("金额元字符串不合法。输入值=" + str);
        }
    }

    public static void main(String[] args) {
        System.out.println(yuanToFen("11.1561"));
    }

    /**
     * 功能描述: 获取税率 1300 ==> 0.13
     *
     * @Author: chenxin
     * @Param: [taxRate]
     * @Date: 2020/4/27
     */
    public static BigDecimal getTaxRateToBigDecimal(Integer taxRate) {
        if (taxRate == null) {
            return BigDecimal.ZERO;
        }

        return new BigDecimal(taxRate).divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 计算商城商品价格 单位为分 取整
     *
     * @param a
     * @param b
     * @return
     */
    public static Integer getMultiplyPrice(BigDecimal a, BigDecimal b) {
        return a.multiply(b).divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
    }

    /**
     * 功能描述: 以xx.xW展示数字 保留一位小数 省略多余的小数
     *
     * @Author: chenxin
     * @Param: [num]
     * @Date: 2020/8/19
     */
    public static String getNumToWan(Integer num) {
        if (num == null) {
            return BigDecimal.ZERO.toString();
        }

        if (num < 1000) {
            return num.toString();
        }

        BigDecimal decimal = new BigDecimal(num).divide(new BigDecimal(10000), 1, BigDecimal.ROUND_DOWN);
        return decimal.toString() + "W";
    }

    /**
     * 获取随机数
     * 
     * @param start 随机数取值起始值
     * @param end 随机数取值结束值
     * @return
     */
    public static int getRandomNum(int start, int end) {
        if (start == end) {
            return start;
        }
        Random rd = new Random();
        if (end > start) {
            return start + rd.nextInt(end - start);
        } else {
            return end + rd.nextInt(start - end);
        }
    }

    /**
     * 功能描述: 为对象设置随机的属性 仅支持基本属性 注意：该类的父类属性并不会赋值
     *
     * @Author: chenxin
     * @Param: [obj]
     * @Date: 2020/8/20
     */
    public static void setRandomDataToObject(Object obj) {
        if (obj == null) {
            return;
        }

        // 得到class
        Class cls = obj.getClass();
        // 得到所有属性
        Field[] fields = cls.getDeclaredFields();
        try {
            for (int i = 0; i < fields.length; i++) {// 遍历

                // 得到属性
                Field field = fields[i];
                // 打开私有访问
                field.setAccessible(true);
                // 获取属性
                String name = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                // 获取属性类型
                String typeName = field.getGenericType().getTypeName();

                int randomNum = getRandomNum(100, 10000000);

                if (typeName.equals("java.lang.Integer")) {
                    Method m = cls.getMethod("get" + name);
                    Integer value = (Integer)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, Integer.class);
                        m.invoke(obj, randomNum);
                    }
                }
                if (typeName.equals("java.lang.Long")) {
                    Method m = cls.getMethod("get" + name);
                    Long value = (Long)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, Long.class);
                        m.invoke(obj, Long.valueOf(randomNum));
                    }
                }
                if (typeName.equals("java.lang.Double")) {
                    Method m = cls.getMethod("get" + name);
                    Double value = (Double)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, Double.class);
                        Double temp = Double.valueOf(randomNum);
                        BigDecimal decimal =
                            new BigDecimal(temp).divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP);
                        m.invoke(obj, decimal.doubleValue());
                    }
                }
                if (typeName.equals("java.lang.String")) {
                    Method m = cls.getMethod("get" + name);
                    String value = (String)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, String.class);
                        String temp = "测试文本-" + randomNum;
                        m.invoke(obj, temp);
                    }
                }
                if (typeName.equals("java.lang.Boolean")) {
                    Method m = cls.getMethod("get" + name);
                    Boolean value = (Boolean)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, Boolean.class);
                        Boolean temp = randomNum % 2 == 0 ? true : false;
                        m.invoke(obj, temp);
                    }
                }
                if (typeName.equals("java.util.Date")) {
                    Method m = cls.getMethod("get" + name);
                    Date value = (Date)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, Date.class);
                        m.invoke(obj, new Date());
                    }
                }
                if (typeName.equals("java.math.BigDecimal")) {
                    Method m = cls.getMethod("get" + name);
                    BigDecimal value = (BigDecimal)m.invoke(obj);
                    if (value == null) {
                        m = cls.getMethod("set" + name, BigDecimal.class);
                        BigDecimal bigDecimal = new BigDecimal(randomNum);
                        m.invoke(obj, bigDecimal);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能描述: 抽奖
     *
     * @Author: chenxin
     * @Param: [map：key：奖品id; value：相对概率(四位) 总和不用等于10000]
     * @Return: [中奖奖品id]
     * @Date: 2021/1/18
     */
    public static Long lottery(Map<Long, Integer> map, Long guaranteedPrizeId) {
        if (map == null || map.size() == 0) {
            return null;
        }

        int sum = map.values().stream().mapToInt(Integer::intValue).sum();
        if (guaranteedPrizeId != null) {
            int temp = 10000;
            int otherSum = temp - sum;
            if (otherSum > 0) {
                // 将不足10000的概率补齐到保底奖品概率中
                map.put(guaranteedPrizeId, Optional.ofNullable(map.get(guaranteedPrizeId)).orElse(0) + otherSum);
            }
        }

        Integer rand = new Random().nextInt(sum) + 1;
        for (Map.Entry<Long, Integer> entry : map.entrySet()) {
            rand -= entry.getValue();
            // 选中
            if (rand <= 0) {
                return entry.getKey();
            }
        }
        return null;
    }

}
